jetcrab\vm\executor\instruction_handlers/stack_ops.rs
1//! # Stack Operations Handler
2//!
3//! Handles all stack manipulation operations in the VM including pushing, popping,
4//! duplicating, and other stack management operations.
5//!
6//! ## Operations Supported
7//!
8//! - **Basic Operations**: push, pop, peek
9//! - **Duplication**: dup, dup2
10//! - **Rearrangement**: swap, rot, over
11//! - **Removal**: drop, drop2, clear
12//! - **Information**: size, is_empty, depth
13//! - **Advanced**: reserve, truncate
14//!
15//! ## Stack Semantics
16//!
17//! - **LIFO**: Last In, First Out stack behavior
18//! - **Type Safety**: All operations maintain type safety
19//! - **Bounds Checking**: Prevents stack underflow/overflow
20//! - **Performance**: Optimized for common operations
21//!
22//! ## Usage
23//!
24//! ```rust
25//! use jetcrab::vm::executor::instruction_handlers::StackOpsHandler;
26//! use jetcrab::vm::executor::traits::StackOperations;
27//!
28//! let mut stack = MyStack::new();
29//! stack.push(Value::Number(42.0));
30//! StackOpsHandler::dup(&mut stack)?;
31//! // Stack now contains: [42.0, 42.0]
32//! ```
33
34use crate::vm::executor::error_handler::ExecutionError;
35use crate::vm::executor::traits::StackOperations;
36use crate::vm::value::Value;
37use crate::vm::types::indices::StackIndex;
38
39/// Handles stack operations for the VM
40pub struct StackOpsHandler;
41
42impl StackOpsHandler {
43 /// Pushes a value onto the stack
44 ///
45 /// Adds a value to the top of the stack.
46 ///
47 /// # Arguments
48 /// * `stack` - The stack to operate on
49 /// * `value` - The value to push onto the stack
50 ///
51 /// # Returns
52 /// * `Ok(())` on success
53 /// * `Err(ExecutionError)` on failure
54 ///
55 /// # Examples
56 ///
57 /// ```rust
58 /// let mut stack = MyStack::new();
59 /// StackOpsHandler::push(&mut stack, Value::Number(42.0))?;
60 /// assert_eq!(stack.pop(), Some(Value::Number(42.0)));
61 /// ```
62 pub fn push<S>(stack: &mut S, value: Value) -> Result<(), ExecutionError>
63 where
64 S: StackOperations,
65 {
66 stack.push(value);
67 Ok(())
68 }
69
70 /// Pops a value from the top of the stack
71 ///
72 /// Removes and returns the top value from the stack.
73 ///
74 /// # Arguments
75 /// * `stack` - The stack to operate on
76 ///
77 /// # Returns
78 /// * `Ok(())` on success
79 /// * `Err(ExecutionError::StackUnderflow)` if stack is empty
80 ///
81 /// # Examples
82 ///
83 /// ```rust
84 /// let mut stack = MyStack::new();
85 /// stack.push(Value::Number(42.0));
86 /// StackOpsHandler::pop(&mut stack)?;
87 /// assert!(stack.is_empty());
88 /// ```
89 pub fn pop<S>(stack: &mut S) -> Result<(), ExecutionError>
90 where
91 S: StackOperations,
92 {
93 stack.pop().ok_or(ExecutionError::StackUnderflow)?;
94 Ok(())
95 }
96
97 /// Duplicates the top value on the stack
98 ///
99 /// Pops the top value and pushes it twice, effectively duplicating it.
100 ///
101 /// # Arguments
102 /// * `stack` - The stack to operate on
103 ///
104 /// # Returns
105 /// * `Ok(())` on success
106 /// * `Err(ExecutionError::StackUnderflow)` if stack is empty
107 ///
108 /// # Examples
109 ///
110 /// ```rust
111 /// let mut stack = MyStack::new();
112 /// stack.push(Value::Number(42.0));
113 /// StackOpsHandler::dup(&mut stack)?;
114 /// // Stack now contains: [42.0, 42.0]
115 /// ```
116 pub fn dup<S>(stack: &mut S) -> Result<(), ExecutionError>
117 where
118 S: StackOperations,
119 {
120 let value = stack.peek().ok_or(ExecutionError::StackUnderflow)?.clone();
121 stack.push(value);
122 Ok(())
123 }
124
125 /// Duplicates the top two values on the stack
126 ///
127 /// Pops the top two values and pushes them twice, effectively duplicating them.
128 ///
129 /// # Arguments
130 /// * `stack` - The stack to operate on
131 ///
132 /// # Returns
133 /// * `Ok(())` on success
134 /// * `Err(ExecutionError::StackUnderflow)` if insufficient operands
135 ///
136 /// # Examples
137 ///
138 /// ```rust
139 /// let mut stack = MyStack::new();
140 /// stack.push(Value::Number(42.0));
141 /// stack.push(Value::Number(100.0));
142 /// StackOpsHandler::dup2(&mut stack)?;
143 /// // Stack now contains: [42.0, 100.0, 42.0, 100.0]
144 /// ```
145 pub fn dup2<S>(stack: &mut S) -> Result<(), ExecutionError>
146 where
147 S: StackOperations,
148 {
149 if stack.len() < 2 {
150 return Err(ExecutionError::StackUnderflow);
151 }
152
153 let b = stack.pop().ok_or(ExecutionError::StackUnderflow)?;
154 let a = stack.pop().ok_or(ExecutionError::StackUnderflow)?;
155
156 stack.push(a.clone());
157 stack.push(b.clone());
158 stack.push(a);
159 stack.push(b);
160
161 Ok(())
162 }
163
164 /// Swaps the top two values on the stack
165 ///
166 /// Exchanges the positions of the top two values on the stack.
167 ///
168 /// # Arguments
169 /// * `stack` - The stack to operate on
170 ///
171 /// # Returns
172 /// * `Ok(())` on success
173 /// * `Err(ExecutionError::StackUnderflow)` if insufficient operands
174 ///
175 /// # Examples
176 ///
177 /// ```rust
178 /// let mut stack = MyStack::new();
179 /// stack.push(Value::Number(42.0));
180 /// stack.push(Value::Number(100.0));
181 /// StackOpsHandler::swap(&mut stack)?;
182 /// // Stack now contains: [100.0, 42.0]
183 /// ```
184 pub fn swap<S>(stack: &mut S) -> Result<(), ExecutionError>
185 where
186 S: StackOperations,
187 {
188 if stack.len() < 2 {
189 return Err(ExecutionError::StackUnderflow);
190 }
191
192 let b = stack.pop().ok_or(ExecutionError::StackUnderflow)?;
193 let a = stack.pop().ok_or(ExecutionError::StackUnderflow)?;
194
195 stack.push(b);
196 stack.push(a);
197
198 Ok(())
199 }
200
201 /// Rotates the top three values on the stack
202 ///
203 /// Moves the third value to the top, shifting the others down.
204 ///
205 /// # Arguments
206 /// * `stack` - The stack to operate on
207 ///
208 /// # Returns
209 /// * `Ok(())` on success
210 /// * `Err(ExecutionError::StackUnderflow)` if insufficient operands
211 ///
212 /// # Examples
213 ///
214 /// ```rust
215 /// let mut stack = MyStack::new();
216 /// stack.push(Value::Number(1.0));
217 /// stack.push(Value::Number(2.0));
218 /// stack.push(Value::Number(3.0));
219 /// StackOpsHandler::rot(&mut stack)?;
220 /// // Stack now contains: [2.0, 3.0, 1.0]
221 /// ```
222 pub fn rot<S>(stack: &mut S) -> Result<(), ExecutionError>
223 where
224 S: StackOperations,
225 {
226 if stack.len() < 3 {
227 return Err(ExecutionError::StackUnderflow);
228 }
229
230 let c = stack.pop().ok_or(ExecutionError::StackUnderflow)?;
231 let b = stack.pop().ok_or(ExecutionError::StackUnderflow)?;
232 let a = stack.pop().ok_or(ExecutionError::StackUnderflow)?;
233
234 stack.push(b);
235 stack.push(c);
236 stack.push(a);
237
238 Ok(())
239 }
240
241 /// Copies the second value to the top of the stack
242 ///
243 /// Pushes a copy of the second value without removing it.
244 ///
245 /// # Arguments
246 /// * `stack` - The stack to operate on
247 ///
248 /// # Returns
249 /// * `Ok(())` on success
250 /// * `Err(ExecutionError::StackUnderflow)` if insufficient operands
251 ///
252 /// # Examples
253 ///
254 /// ```rust
255 /// let mut stack = MyStack::new();
256 /// stack.push(Value::Number(42.0));
257 /// stack.push(Value::Number(100.0));
258 /// StackOpsHandler::over(&mut stack)?;
259 /// // Stack now contains: [42.0, 100.0, 42.0]
260 /// ```
261 pub fn over<S>(stack: &mut S) -> Result<(), ExecutionError>
262 where
263 S: StackOperations,
264 {
265 if stack.len() < 2 {
266 return Err(ExecutionError::StackUnderflow);
267 }
268
269 let values = stack.stack_mut();
270 let second_value = values.get(StackIndex::new(values.size() - 2)).unwrap().clone();
271 stack.push(second_value);
272
273 Ok(())
274 }
275
276 /// Removes the top value from the stack
277 ///
278 /// Pops and discards the top value from the stack.
279 ///
280 /// # Arguments
281 /// * `stack` - The stack to operate on
282 ///
283 /// # Returns
284 /// * `Ok(())` on success
285 /// * `Err(ExecutionError::StackUnderflow)` if stack is empty
286 pub fn drop<S>(stack: &mut S) -> Result<(), ExecutionError>
287 where
288 S: StackOperations,
289 {
290 stack.pop().ok_or(ExecutionError::StackUnderflow)?;
291 Ok(())
292 }
293
294 /// Removes the top two values from the stack
295 ///
296 /// Pops and discards the top two values from the stack.
297 ///
298 /// # Arguments
299 /// * `stack` - The stack to operate on
300 ///
301 /// # Returns
302 /// * `Ok(())` on success
303 /// * `Err(ExecutionError::StackUnderflow)` if insufficient operands
304 pub fn drop2<S>(stack: &mut S) -> Result<(), ExecutionError>
305 where
306 S: StackOperations,
307 {
308 if stack.len() < 2 {
309 return Err(ExecutionError::StackUnderflow);
310 }
311
312 stack.pop().ok_or(ExecutionError::StackUnderflow)?;
313 stack.pop().ok_or(ExecutionError::StackUnderflow)?;
314
315 Ok(())
316 }
317
318 /// Clears all values from the stack
319 ///
320 /// Removes all values from the stack, leaving it empty.
321 ///
322 /// # Arguments
323 /// * `stack` - The stack to operate on
324 ///
325 /// # Returns
326 /// * `Ok(())` on success
327 pub fn clear<S>(stack: &mut S) -> Result<(), ExecutionError>
328 where
329 S: StackOperations,
330 {
331 stack.clear();
332 Ok(())
333 }
334
335 /// Gets the current size of the stack
336 ///
337 /// Pushes the number of values currently on the stack.
338 ///
339 /// # Arguments
340 /// * `stack` - The stack to operate on
341 ///
342 /// # Returns
343 /// * `Ok(())` on success
344 ///
345 /// # Examples
346 ///
347 /// ```rust
348 /// let mut stack = MyStack::new();
349 /// stack.push(Value::Number(42.0));
350 /// stack.push(Value::Number(100.0));
351 /// StackOpsHandler::size(&mut stack)?;
352 /// assert_eq!(stack.pop(), Some(Value::Number(2.0)));
353 /// ```
354 pub fn size<S>(stack: &mut S) -> Result<(), ExecutionError>
355 where
356 S: StackOperations,
357 {
358 let size = stack.size();
359 stack.push(Value::Number(size as f64));
360 Ok(())
361 }
362
363 /// Checks if the stack is empty
364 ///
365 /// Pushes a boolean indicating whether the stack is empty.
366 ///
367 /// # Arguments
368 /// * `stack` - The stack to operate on
369 ///
370 /// # Returns
371 /// * `Ok(())` on success
372 ///
373 /// # Examples
374 ///
375 /// ```rust
376 /// let mut stack = MyStack::new();
377 /// StackOpsHandler::is_empty(&mut stack)?;
378 /// assert_eq!(stack.pop(), Some(Value::Boolean(true)));
379 /// ```
380 pub fn is_empty<S>(stack: &mut S) -> Result<(), ExecutionError>
381 where
382 S: StackOperations,
383 {
384 let is_empty = stack.is_empty();
385 stack.push(Value::Boolean(is_empty));
386 Ok(())
387 }
388
389 /// Peeks at the top value without removing it
390 ///
391 /// Pushes a copy of the top value without modifying the stack.
392 ///
393 /// # Arguments
394 /// * `stack` - The stack to operate on
395 ///
396 /// # Returns
397 /// * `Ok(())` on success
398 /// * `Err(ExecutionError::StackUnderflow)` if stack is empty
399 ///
400 /// # Examples
401 ///
402 /// ```rust
403 /// let mut stack = MyStack::new();
404 /// stack.push(Value::Number(42.0));
405 /// StackOpsHandler::peek(&mut stack)?;
406 /// // Stack now contains: [42.0, 42.0]
407 /// ```
408 pub fn peek<S>(stack: &mut S) -> Result<(), ExecutionError>
409 where
410 S: StackOperations,
411 {
412 let value = stack.peek().ok_or(ExecutionError::StackUnderflow)?.clone();
413 stack.push(value);
414 Ok(())
415 }
416
417 /// Gets the depth of the stack
418 ///
419 /// Pushes the current depth (number of values) on the stack.
420 ///
421 /// # Arguments
422 /// * `stack` - The stack to operate on
423 ///
424 /// # Returns
425 /// * `Ok(())` on success
426 pub fn depth<S>(stack: &mut S) -> Result<(), ExecutionError>
427 where
428 S: StackOperations,
429 {
430 let depth = stack.len();
431 stack.push(Value::Number(depth as f64));
432 Ok(())
433 }
434
435 /// Reserves space on the stack
436 ///
437 /// Ensures the stack has at least the specified capacity.
438 ///
439 /// # Arguments
440 /// * `stack` - The stack to operate on
441 /// * `capacity` - The minimum capacity to reserve
442 ///
443 /// # Returns
444 /// * `Ok(())` on success
445 pub fn reserve<S>(stack: &mut S, capacity: usize) -> Result<(), ExecutionError>
446 where
447 S: StackOperations,
448 {
449 let stack_mut = stack.stack_mut();
450 stack_mut.values.reserve(capacity);
451 Ok(())
452 }
453
454 /// Truncates the stack to a specific size
455 ///
456 /// Removes values from the top of the stack until it reaches the specified size.
457 ///
458 /// # Arguments
459 /// * `stack` - The stack to operate on
460 /// * `size` - The target size for the stack
461 ///
462 /// # Returns
463 /// * `Ok(())` on success
464 /// * `Err(ExecutionError::StackUnderflow)` if target size is larger than current size
465 pub fn truncate<S>(stack: &mut S, size: usize) -> Result<(), ExecutionError>
466 where
467 S: StackOperations,
468 {
469 let current_size = stack.len();
470 if size > current_size {
471 return Err(ExecutionError::StackUnderflow);
472 }
473
474 let to_remove = current_size - size;
475 for _ in 0..to_remove {
476 stack.pop().ok_or(ExecutionError::StackUnderflow)?;
477 }
478
479 Ok(())
480 }
481}